import cmd
import sys
import os

# 使用base code 的common.py
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(parent_dir)
from base_code.common import *


# --- 新的工具定义 ---
# 一个列出给定目录下文件的工具demo
def list_directory_contents(path: str = '.') -> str:
    """一个列出目录内容的工具函数。"""
    try:
        if not os.path.isdir(path):
            return f"错误: '{path}' 不是一个有效的目录。"

        files = os.listdir(path)
        if not files:
            return f"目录 '{path}' 为空。"

        return f"目录 '{path}' 下的内容:\n- " + "\n- ".join(files)
    except Exception as e:
        return f"执行时发生错误: {e}"


# 创建工具实例
list_files_tool = Tool(
    name="list_files",
    description="列出指定路径下的所有文件和目录。",
    function=list_directory_contents,
    required_args=["path"]
)



class BDIAgent:
    """
    内部工作流程遵循“感知-决策-执行”循环。
    """

    def __init__(self):
        """
        初始化Agent。
        - Beliefs (信念): 存储数据的字典。
        - Plans (计划库): 将命令映射到具体的执行函数。
        """
        self.beliefs = {}
        self._plans = {
            'set': self._execute_set,
            'get': self._execute_get,
            'delete': self._execute_delete,
            'list': self._execute_list,
            'list_tools': self._execute_list_tools,  # 新增
            'use_tool': self._execute_tool_call,  # 新增
        }
        self.tool_system = ToolSystem()  # 新增：初始化工具系统
        self.tool_system.register_tool(list_files_tool)  # 新增：注册工具
        print("💡 BDIAgent 已初始化。内部循环已建立，并加载了工具系统。")

    def run(self, command, raw_arg):
        # 1. 感知 (Perception): 解析原始输入，形成结构化愿望或发现错误
        perception_status, perception_result = self._perceive(command, raw_arg)
        if perception_status == 'error':
            return perception_result  # 如果感知阶段就发现错误，直接返回错误信息

        # 2. 决策 (Deliberation): 根据愿望选择一个计划（意图）
        desire = perception_result
        intention, plan_args = self._deliberate(desire)
        if not intention:
            return f"❌ 内部错误: Agent没有针对愿望 '{desire[0]}' 的计划。"

        # 3. 执行 (Execution): 执行选定的计划
        result = intention(*plan_args)

        return result

    def _perceive(self, command, raw_arg):
        """
        感知阶段：解析并验证输入，将其转换为结构化的“愿望”。
        所有输入校验逻辑都集中在此处。
        """
        arg = raw_arg.strip()

        if command == 'set':
            parts = arg.split(None, 1)
            if len(parts) < 2:
                return 'error', "❌ 错误: 'set' 命令需要一个键和一个值。\n   用法: set <key> <value>"
            key, value = parts
            return 'success', ('set', key, value)

        elif command in ['get', 'delete']:
            if not arg:
                return 'error', f"❌ 错误: '{command}' 命令需要一个键。\n   用法: {command} <key>"
            return 'success', (command, arg)

        elif command == 'list':
            return 'success', ('list',)

        # 新增：感知 'list_tools' 命令
        elif command == 'list_tools':
            return 'success', ('list_tools',)

        # 新增：感知 'use_tool' 命令
        elif command == 'use_tool':
            parts = arg.split(None, 1)
            if not parts:
                return 'error', "❌ 错误: 'use_tool' 需要工具名称。\n   用法: use_tool <tool_name> [arg1=val1 ...]"

            tool_name = parts[0]
            kwargs_str = parts[1] if len(parts) > 1 else ""

            try:
                # 解析 key=value 格式的参数
                kwargs = dict(kv.split('=', 1) for kv in kwargs_str.split())
                return 'success', ('use_tool', tool_name, kwargs)
            except ValueError:
                return 'error', "❌ 错误: 参数格式必须是 'key=value'。\n   示例: use_tool list_files path=."
        else:
            return 'error', f"❌ 内部错误: 感知到未知命令 '{command}'"

    def _deliberate(self, desire):
        command = desire[0]
        args = desire[1:]
        plan_to_execute = self._plans.get(command)
        return plan_to_execute, args

    def _execute_set(self, key, value):
        self.beliefs[key] = value
        return f"✅ 成功: '{key}' 已设置为 '{value}'"

    def _execute_get(self, key):
        """Plan for 'get' desire: 查询信念。"""
        value = self.beliefs.get(key)
        if value is not None:
            return f"➡️ {key} = {value}"
        else:
            return f"🔍 未找到键: '{key}'"

    def _execute_delete(self, key):
        """Plan for 'delete' desire: 从信念中移除。"""
        if key in self.beliefs:
            del self.beliefs[key]
            return f"✅ 成功: 键 '{key}' 已被删除。"
        else:
            return f"🔍 未找到键: '{key}'"

    def _execute_list(self):
        """Plan for 'list' desire: 列出所有信念。"""
        if not self.beliefs:
            return "ℹ️  数据库为空。"

        lines = ["📋 当前存储的所有数据:"]
        max_key_len = max(len(k) for k in self.beliefs.keys()) if self.beliefs else 0
        for key, value in self.beliefs.items():
            lines.append(f"  - {key:<{max_key_len}} : {value}")
        return "\n".join(lines)

    # 新增：执行列出工具的计划
    def _execute_list_tools(self):
        tools = self.tool_system.list_tools()
        if not tools:
            return "ℹ️  当前没有可用的工具。"

        lines = ["🛠️ 可用工具列表:"]
        for tool in tools:
            lines.append(f"  - 名称: {tool['name']}")
            lines.append(f"    描述: {tool['description']}")
        return "\n".join(lines)

    # 新增：执行调用工具的计划
    def _execute_tool_call(self, tool_name, kwargs):
        try:
            tool = self.tool_system.get_tool(tool_name)
            print(f"⚙️ 正在执行工具 '{tool_name}'...")
            result = tool(**kwargs)
            return f"工具 '{tool_name}' 执行结果:\n---\n{result}\n---"
        except Exception as e:
            return f"❌ 工具执行失败: {e}"


class ToolAgentShell(cmd.Cmd):
    """
    一个极致简化的交互式Shell，作为纯粹的用户界面。
    它不包含任何业务逻辑或输入校验。
    """
    lines = [
        "     欢迎使用 SimpleAgent v1.0 (BDI工具版)",
        " ",
        "UI层完全简化，所有逻辑由Agent的P-D-A循环处理",
        " ",
        "set <key> <value>  - 设置一个键值对",
        "get <key>          - 获取一个键对应的值",
        "delete <key>       - 删除一个键值对",
        "list_tools         - 列出所有工具",
        "use_tool <tool> <param>   - 列出所有存储的键值对",
        "list               - 列出所有存储的键值对",
        "help               - 显示帮助信息",
        "exit / quit        - 退出程序"
    ]
    intro = create_aligned_intro(lines)
    prompt = "agent> "

    def __init__(self):
        super().__init__()
        self.agent = BDIAgent()

    def do_list_tools(self, arg):
        """列出所有可用工具。"""
        result = self.agent.run('list_tools', arg)
        print(result)

    def do_use_tool(self, arg):
        """使用一个指定的工具。"""
        result = self.agent.run('use_tool', arg)
        print(result)

    def do_set(self, arg):
        """将原始'set'输入传递给Agent。"""
        result = self.agent.run('set', arg)
        print(result)

    def do_get(self, arg):
        """将原始'get'输入传递给Agent。"""
        result = self.agent.run('get', arg)
        print(result)

    def do_delete(self, arg):
        """将原始'delete'输入传递给Agent。"""
        result = self.agent.run('delete', arg)
        print(result)

    def do_list(self, arg):
        """将原始'list'输入传递给Agent。"""
        result = self.agent.run('list', arg)
        print(result)

    def do_exit(self, arg):
        """退出交互式Shell。"""
        print("\n👋 感谢使用，再见！")
        return True

    def do_quit(self, arg):
        """`quit` 是 `exit` 的别名。"""
        return self.do_exit(arg)

    def do_EOF(self, arg):
        """处理 Ctrl+D (EOF)，实现优雅退出。"""
        print()
        return self.do_exit(arg)

    def help_set(self):
        print("\n".join([
            "命令: set <key> <value>",
            "功能: 创建或更新一个键值对。",
            "示例:",
            "  set name 'John Doe'",
            "  set age 30"
        ]))

    def default(self, line):
        """处理未知命令。"""
        print(f"❌ 未知命令: '{line}'。输入 'help' 查看可用命令列表。")


def main():
    """程序主入口。"""
    try:
        ToolAgentShell().cmdloop()
    except KeyboardInterrupt:
        print("\n👋 检测到中断，程序退出。")
        sys.exit(0)

if __name__ == '__main__':
    main()